/**
 * \file kernel/syscall.c
 * \author Davide Gessa
 * \date 10-12-09
 */
#include <syscall.h>
#include <types.h>
#include <arch.h>
#include <debug.h>
#include <util.h>
#include <task/task.h>
#include <task/term.h>
#include <driver.h>
#include <video.h>
#include <driver.h>
#include <fs/fs.h>
#include <fs/file.h>
#include <fs/dir.h>
#include <main.h>
#include <debug.h>
#include <config.h>
#include <video.h>



/**
 * Lista delle syscalls
 */
syscall_t syscalls[] =
	{
		////////////////////////////
		// System misc 1 : 20
		{ .call = (void *) syscall_info_get },
		{ .call = (void *) debug_puts },
		{ .call = (void *) syscall_test },
		{ .call = (void *) shutdown },

		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		{ .call = (void *) syscall_void },
		
		
		///////////////////////////////
		// VFS 20 : 40
		{ .call = (void *) fs_mount },
		{ .call = (void *) fs_umount },
		
		// Directory
		{ .call = (void *) fs_readdir },
		{ .call = (void *) fs_opendir },
		{ .call = (void *) fs_closedir },
		{ .call = (void *) fs_rewinddir },
		{ .call = (void *) fs_makedir },
		{ .call = (void *) fs_rmdir },
		
		// File
		{ .call = (void *) fs_read },
		{ .call = (void *) fs_open },
		{ .call = (void *) fs_close },
		{ .call = (void *) fs_write },
		{ .call = (void *) fs_seek },
		
		// Link
		{ .call = (void *) fs_link },
		{ .call = (void *) fs_unlink },
	};


/**
 * Numero totale delle syscalls
 */
uint32_t syscalls_number = sizeof(syscalls) / sizeof(syscall_t);


/**
 * Effetua una chiamata ad una call
 * 
 * \param call numero della syscall
 * \param ebx parametro 1
 * \param ecx parametro 2
 * \param edx parametro 3
 */
int syscall_call(uint32_t call, uint32_t ebx, uint32_t ecx, uint32_t edx)
{
	regs_t reg;
	reg.eax = call;
	reg.ebx = ebx; 
	reg.ecx = ecx; 
	reg.edx = edx; 
	asm("movl %0, %%eax\n\t": : "g" (&reg));
	
	asm ("int %0\n" : : "g" (SYSCALL_INT));
	
	asm ("movl %%eax, %0\n\t" : "=r" (reg.eax));
	return reg.eax;
}


/**
 * Handler delle chiamate alla syscall
 * 
 * \param r tutti i registri salvati al momento dell'interruzione
 */
void syscall_callback(regs_t *r)
{	
	regs_t *reg;
	int ret;
	
	// Preleva gli argomenti
	asm ("movl %%eax, %0\n\t" : "=r" (reg));
		 
	
	if(reg->eax > syscalls_number)
		return;
		
	ret = syscalls[reg->eax].call(reg->ebx, reg->ecx, reg->edx);		
	
	// Restituisce il valore di ritorno
	asm("movl %0, %%eax\n\t": : "g" (ret)); 
}



/**
 * Inizializza le syscall
 */
void syscall_init()
{
	DEBUGP("syscall_init()\n");

//	syscall_call(2, "task caricato da file! syscall test!\n", 0, 0);
}





/**
 * Syscall di test
 */
uint32_t syscall_test()
{
	puts("test!\n");
	
	return 0;
}


/**
 * Syscall vuota
 */
uint32_t syscall_void()
{
	return 0;
}



/**
 * Restituisce le info del sistema
 * 
 * \param ki puntatore ad una struttura sysinfo
 */
uint32_t syscall_info_get(sysinfo_t *ki)
{
	strcpy(ki->name, NAME);
	strcpy(ki->ver, VER);
	strcpy(ki->rev, REV);
	strcpy(ki->date, __DATE__);
	strcpy(ki->time, __TIME__);
	strcpy(ki->arch, ARCH);
	strcpy(ki->vend, CPU_VENDOR);
}
